package com.t3go.t3_map;

import android.content.Context;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Lifecycle;

import com.alibaba.android.arouter.launcher.ARouter;
import com.shareware.common.utils.LogExtKt;
import com.t3go.passenger.base.entity.AddressEntity;
import com.t3go.passenger.base.utils.JsonUtils;
import com.t3go.passenger.router.ILocationRouterService;
import com.t3go.passenger.router.IMapArouterService;
import com.t3go.t3_map.base.LifecycleProvider;
import com.t3go.t3_map.base.T3FMapPlatformViewFactory;
import com.t3go.t3_map.entity.Coordinate;
import com.t3go.t3_map.entity.DriveRouteArgs;
import com.t3go.t3_map.entity.SearchPoiTypeCodesArgs;
import com.t3go.t3_map.entity.WalkRouteArgs;
import com.t3map.api.T3MapsInitializer;
import com.t3map.api.map.entity.LocationEntity;
import com.t3map.api.map.entity.RouteInfoEntity;
import com.t3map.api.map.model.T3LatLng;
import com.t3map.api.service.IT3SearchService;
import com.t3map.api.service.T3RouteSearchManager;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.embedding.engine.plugins.lifecycle.HiddenLifecycleReference;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;

/**
 * T3MapPlugin
 */
public class T3MapPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {

    private static final String TAG = "T3MapPlugin";
    /// The MethodChannel that will the communication between Flutter and native Android
    ///
    /// This local reference serves to register the plugin with the Flutter Engine and unregister it
    /// when the Flutter Engine is detached from the Activity
    private static final String CLASS_NAME = "T3MapPlugin";
    private static final String VIEW_TYPE = "com.t3.map.flutter.mapview";
    private FlutterPluginBinding mFlutterPluginBinding;
    private MethodChannel channel;
    private Lifecycle lifecycle;
    private Context mContext;

    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
        mContext = flutterPluginBinding.getApplicationContext();

        mFlutterPluginBinding = flutterPluginBinding;
        flutterPluginBinding.getPlatformViewRegistry().registerViewFactory(VIEW_TYPE,
                new T3FMapPlatformViewFactory(flutterPluginBinding.getBinaryMessenger(), new LifecycleProvider() {
                    @Nullable
                    @Override
                    public Lifecycle getLifecycle() {
                        return lifecycle;
                    }
                }));

        channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "t3_map");
        channel.setMethodCallHandler(this);
        FlutterMapPlugin.initMethodChannel(channel);
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
        String arguments = call.arguments != null ? call.arguments.toString() : null;
        if ("getPlatformVersion".equals(call.method)) {
            result.success("Android " + android.os.Build.VERSION.RELEASE);
        } else if ("walkingRoute#calculate".equals(call.method)) {
            walkingRoute(arguments, result);
        } else if ("driveRoute#calculate".equals(call.method)) {
            driveRoute(arguments, result);
        } else if ("searchPoiTypeCode".equals(call.method)) {
            searchPoiTypeCodes(arguments, result);
        } else {
            result.notImplemented();
        }
    }

    private void walkingRoute(String args, MethodChannel.Result callback) {
        LogExtKt.log(TAG, "walkingRoute -> args = " + args);
        WalkRouteArgs params = JsonUtils.fromJson(args, WalkRouteArgs.class);
        if (params == null || params.getStart() == null || params.getEnd() == null) {
            LogExtKt.log(TAG, "walkingRoute -> 参数无效, args = " + args);
            return;
        }
        Coordinate start = params.getStart();
        Coordinate end = params.getEnd();
        if (start.getLatitude() == 0 || start.getLongitude() == 0 || end.getLatitude() == 0 || end.getLongitude() == 0) {
            LogExtKt.log(TAG, "walkingRoute -> 参数无效, args = " + args);
            return;
        }
        AddressEntity origin = new AddressEntity(start.getLatitude(), start.getLongitude(), null);
        AddressEntity dest = new AddressEntity(end.getLatitude(), end.getLongitude(), null);

        IMapArouterService service = ARouter.getInstance().navigation(IMapArouterService.class);
        service.walkRouteSearch(origin, dest, true, data -> {
            HashMap<String, Object> result = new HashMap<>();
            List<HashMap<String, Object>> routes = new ArrayList<>();
            if (data != null) {
                HashMap<String, Object> route = new HashMap<>();
                route.put("distance", data.getPlanTrip()); // 行驶距离,单位：米
                route.put("duration", data.getPlanTime()); // 预计行驶时间,单位：秒
                route.put("polyline", convertLatLng(data.getLatLngList()));
                routes.add(route);
            }
            result.put("routes", routes);
            LogExtKt.log(TAG, "walkingRoute -> result = " + JsonUtils.toJson(result));
            if (callback != null) {
                callback.success(JsonUtils.toJson(result));
            }
        });
    }

    private void searchPoiTypeCodes(String args, MethodChannel.Result callback) {
        SearchPoiTypeCodesArgs params = JsonUtils.fromJson(args, SearchPoiTypeCodesArgs.class);
        if (params == null) {
            LogExtKt.log(TAG, "searchPoiTypeCodes -> 参数无效, args = " + args);
            return;
        }
        LogExtKt.log(TAG, "searchPoiTypeCodes -> args = " + args);
        ILocationRouterService service = ARouter.getInstance().navigation(ILocationRouterService.class);
        service.poiSearch(params.getKeyword(), params.getPoiType(), params.getLatLng(), params.getRadius(), list -> {
            List<String> codes = new ArrayList<>();
            if (list != null) {
                for (AddressEntity item : list) {
                    codes.add(item.getTypeCode());
                }
            }
            LogExtKt.log(TAG, "searchPoiTypeCodes -> typeCods = " + codes);
            if (callback != null) {
                callback.success(JsonUtils.toJson(codes));
            }
        });
    }

    private void driveRoute(String args, MethodChannel.Result callback) {
        DriveRouteArgs params = JsonUtils.fromJson(args, DriveRouteArgs.class);

        HashMap<String, Object> result = new HashMap<>();

        if (params == null) {
            LogExtKt.log(TAG, "driveRoute -> 参数无效, args = " + args);
            result.put("error", "参数错误");
            if (callback != null) {
                callback.success(JsonUtils.toJson(result));
            }
            return;
        }

        Coordinate origin = params.getOrigin();
        Coordinate destination = params.getDestination();

        if (origin == null || destination == null) {
            LogExtKt.log(TAG, "driveRoute -> 参数无效, args = " + args);
            result.put("error", "起终点不能为空");
            if (callback != null) {
                callback.success(JsonUtils.toJson(result));
            }
            return;
        }

        int mapType = params.getMapType() == T3MapsInitializer.MAP_TYPE_TENCENT ? T3MapsInitializer.MAP_TYPE_TENCENT : T3MapsInitializer.MAP_TYPE_AMAP;
        IT3SearchService service = T3RouteSearchManager.getInstance(mapType);
        if (service == null) {
            callback.success(null);
            return;
        }
        List<LocationEntity> locations = new ArrayList<>();
        locations.add(new LocationEntity(origin.getLatitude(), origin.getLongitude()));
        List<Coordinate> wayPoints = params.getVia();
        if (wayPoints != null) {
            for (Coordinate item : wayPoints) {
                locations.add(new LocationEntity(item.getLatitude(), item.getLongitude()));
            }
        }
        locations.add(new LocationEntity(destination.getLatitude(), destination.getLongitude()));
        service.routeSearchByMap2(locations, paths -> {
            HashMap<String, Object> dataMap = new HashMap<>();
            if (paths != null && paths.size() > 0) {
                List<HashMap<String, Object>> routes = new ArrayList<>();
                for (RouteInfoEntity path : paths) {
                    HashMap<String, Object> route = new HashMap<>();
                    route.put("duration", path.getPlanTime());
                    route.put("distance", path.getPlanTrip());
                    route.put("tolls", path.getTollFee());
                    route.put("trafficLightCount", path.getTrafficLightCount());
                    route.put("polyline", convertLatLng(path.getLatLngList()));
                    route.put("tag", path.getLabel());
                    routes.add(route);
                }
                dataMap.put("routes", routes);
            } else {
                dataMap.put("error", "路线获取异常");
            }
            callback.success(JsonUtils.toJson(dataMap));
        });
    }

    private String convertLatLng(List<T3LatLng> points) {
        if (points == null || points.isEmpty()) {
            return null;
        }
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < points.size(); i++) {
            T3LatLng item = points.get(i);
            if (item == null) {
                continue;
            }
            if (i > 0) {
                builder.append(";");
            }
            builder.append(item.lng).append(",").append(item.lat);
        }
        return builder.toString();
    }

    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
        LogExtKt.log(CLASS_NAME, "onDetachedFromEngine==>");
        mFlutterPluginBinding = null;
        channel.setMethodCallHandler(null);
    }

    // ActivityAware
    @Override
    public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
        LogExtKt.log(CLASS_NAME, "onAttachedToActivity==>");
        HiddenLifecycleReference reference =
                (HiddenLifecycleReference) binding.getLifecycle();
        lifecycle = reference.getLifecycle();
    }

    @Override
    public void onDetachedFromActivity() {
        LogExtKt.log(CLASS_NAME, "onDetachedFromActivity==>");
        lifecycle = null;
    }

    @Override
    public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
        LogExtKt.log(CLASS_NAME, "onReattachedToActivityForConfigChanges==>");
        onAttachedToActivity(binding);
    }

    @Override
    public void onDetachedFromActivityForConfigChanges() {
        LogExtKt.log(CLASS_NAME, "onDetachedFromActivityForConfigChanges==>");
        this.onDetachedFromActivity();
    }
}
